package com.atguigu.gmall.index.aspect;

import com.alibaba.fastjson.JSON;
import com.atguigu.gmall.index.annotation.GmallCache;
import com.atguigu.gmall.pms.entity.CategoryEntity;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.util.Arrays;


@Component
@Aspect
public class GmallCacheAspect {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private RedissonClient redissonClient;


    @Around("@annotation(com.atguigu.gmall.index.annotation.GmallCache)")
    public Object cacheAroundAdvice(ProceedingJoinPoint point) throws Throwable {

        //返回的结果
        Object result;

        //获取连接点
        MethodSignature signature = (MethodSignature)point.getSignature();
        //获取当前方法的注解信息
        GmallCache gmallCache = signature.getMethod().getAnnotation(GmallCache.class);
        String prefix = gmallCache.prefix();
        //组装成key
        String key = prefix + Arrays.asList(point.getArgs());
        // 1 .查询缓存
         result = cacheHit(signature, key);
         if (result != null) {
             return result;
         }
        //2.缓存为空
        //2.1 加锁
        RLock lock = redissonClient.getLock("lock" +Arrays.asList(point.getArgs()));
        lock.lock();
        //2.2再次检查缓存是否有数据
       result = cacheHit(signature, key);
       if (result != null) {
           lock.unlock();
           return result;
       }
       //执行目标方法
        result = point.proceed(point.getArgs());
       //将返回结果写入缓存
        redisTemplate.opsForValue().set(key,JSON.toJSONString(result));
        lock.unlock();
        return result;
    }

    /**
     * 查询是否有缓存数据，封装结果
     * @param signature
     * @param key
     * @return
     */
    private Object cacheHit(MethodSignature signature ,String key) {
        String cache = redisTemplate.opsForValue().get(key);
        if (StringUtils.isNotBlank(cache)) {
            Class returnType = signature.getReturnType();
            return JSON.parseObject(cache, returnType);
        }else {
            return null;
        }
    }
}
